import OpenFileDialog from '@/components/OpenFileDialog';
import { Theme } from '@/config/theme';
import { deepClone, getAsyncTime } from '@/ts/base/common';
import { XThing } from '@/ts/base/schema';
import orgCtrl from '@/ts/controller';
import { ITarget } from '@/ts/core';
import { Form } from '@/ts/core/thing/standard/form';
import { Sequence } from '@/ts/core/thing/standard/sequence';
import WorkFormService from '@/ts/scripting/core/services/WorkFormService';
import { FormChangeEvent } from '@/ts/scripting/core/types/rule';
import { DetailOperationType } from '@/ts/scripting/core/types/service';
import * as el from '@/utils/excel';
import { IBelong } from '@/utils/excel';
import { exportToExcel } from '@/utils/export';
import { InputNumber, Modal, Tabs, message } from 'antd';
import ArrayStore from 'devextreme/data/array_store';
import CustomStore from 'devextreme/data/custom_store';
import _, { cloneDeep } from 'lodash';
import type { TabBarExtraContent } from 'rc-tabs/lib/interface';
import React, { useEffect, useRef, useState } from 'react';
import { AiFillCopy, AiFillEdit, AiFillRest } from 'react-icons/ai';
import { MdPrint } from 'react-icons/md';
import { command, kernel, model, parseAvatar, schema } from '../../../ts/base';
import { EditModal } from '../editModal';
import GenerateThingTable from '../generate/thingTable';
import {
  Uploader,
  directImport,
  generating,
  generatingMatch,
  insertData,
  matching,
  showErrors,
} from '../uploadTemplate';
import SplitHandler from '@/ts/scripting/core/rule/SplitHandler';
import Decimal from 'decimal.js';

const pattern = /^T\d+$/;
interface FormProps {
  activeTabKey?: string;
  allowEdit: boolean;
  form: schema.XForm;
  info: model.FormInfo;
  allowLabelPrint?: boolean;
  service: WorkFormService;
  node: model.WorkNodeModel;
  instanceData?: model.InstanceDataModel;
  index: number;
}

const DetailTable: React.FC<FormProps> = (props) => {
  const form = props.form;
  const info = props.info;
  if (!props.service.model.fields[form.id]) return <></>;
  const fields = props.service.model.fields[form.id];
  const operateRule = {
    allowAdd: info?.allowAdd ?? true,
    allowEdit: info?.allowEdit ?? true,
    allowSelect: info?.allowSelect ?? true,
    allowSelectFile: info?.allowSelectFile ?? false,
    autoFill: info?.autoFill ?? false,
    autoAll: info?.autoAll ?? false,
    isAutoAll: info?.isAutoAll ?? false,
  };
  const formData = useRef(props.service.getFormData(props.form, props.node.id, '子表'));
  const [data, setData] = useState(formData.current);
  const [selectKeys, setSelectKeys] = useState<string[]>([]);
  const [differences, setDifferences] = useState<any[]>([]);
  const [center, setCenter] = useState(<></>);
  const loadFields = () => {
    var newFields: model.FieldModel[] = deepClone(props.service.model.fields[form.id]);
    if (data.afterTempId != undefined && data.afterTempId.length > 0) {
      if (newFields.every((a) => a.id != 'thingId')) {
        newFields.unshift({
          id: 'thingId',
          code: 'thingId',
          name: '唯一标识',
          valueType: '描述型',
          remark: '由系统生成的唯一标记,无实义.',
          options: {
            fixed: true,
            visible: true,
          },
        } as model.FieldModel);
      }
    } else {
      newFields = newFields.filter((a) => a.code != 'thingId');
    }
    return newFields;
  };
  useEffect(() => {
    var after = formData?.current.after.at(-1);
    if (after) {
      after.name = props.form.name;
    }
    const model = props.service.model;
    const formId = props.form.id;
    if (model.data[formId]) {
      const temp =
        model.data[formId]?.filter((a) => a.nodeId != formData?.current.nodeId) ?? {};
      model.data[formId] = [...temp, formData.current];
    } else {
      model.data[formId] = [formData.current];
    }
    props.service.onDetailDataChanged(props.form.id, 'all', model.data[formId][0].after);
    if (info?.allowShowChangeData) {
      if (
        (formData.current.after as any[])?.length > 0 &&
        (formData.current.before as any[])?.length > 0
      ) {
        let arr: any[] = [
          ...differences,
          ...findDifferentValues(
            formData.current.after as any[],
            formData.current.before as any[],
          ),
        ];
        if (arr.length > 0) {
          let newArr = info.showChangeData?.map((item: any) => item.id) ?? [];
          newArr.filter((item) => !arr.includes(item));
          arr.push(...newArr);
        }

        setDifferences(arr);
      }
    }
  }, [data]);

  useEffect(() => {
    const id = props.service?.command.subscribe((type, cmd, args) => {
      if (args.formId == props.form?.id) {
        switch (type) {
          case 'change':
            switch (cmd) {
              case 'result':
                switch (args.type) {
                  case 'add':
                    formData.current.after.push(args.value);
                    break;
                  case 'update':
                    formData.current.after = formData.current.after.map((item) => {
                      if (item.id === args.destId) {
                        return args.value;
                      } else {
                        return item;
                      }
                    });
                    break;
                }
                break;
              case 'combination':
                formData.current.after = args.data;
                break;
              case 'assignment':
                formData.current.after = args.data;
                formData.current.before = args.data;
                break;
            }
            break;
        }
        setData({ ...formData.current });
      }
    });
    operateRule.autoFill && loadAutoFillData();

    const extraParams = props.service?.extraParams;
    if (
      extraParams &&
      typeof extraParams.id === 'string' &&
      extraParams.type === 'orderHandler' &&
      !props.index
    ) {
      loadAutoOrderData(extraParams.id);
    }
    return () => {
      props.service?.command.unsubscribe(id!);
    };
  }, []);

  useEffect(() => {
    if (props.instanceData) {
      const data =
        props.instanceData.node.detailForms.length > 0
          ? props.instanceData.data[props.instanceData.node.detailForms[0].id][0].after
          : [];
      insertData(props.service.belong, fields, data, formData.current, () =>
        setData({ ...formData.current }),
      );
    }
  }, [props.instanceData]);

  const loadAutoOrderData = async (id: string) => {
    const order = await props.service.belong.resource.orderColl.find([id]);
    if (Array.isArray(order) && order.length > 0) {
      const values = order as unknown as XThing[];
      formData.current.before = _.cloneDeep(values);
      const detailToDetailRule = props.node.formRules.find(
        (i) => i.ruleType === 'detailToDetail',
      );
      if (detailToDetailRule) {
        detailToDetail(values, detailToDetailRule, 'add');
      }
      formData.current.after = values;
      setData({ ...formData.current });
    }
  };

  const loadAutoFillData = async () => {
    const metaForm = new Form(form, props.service.belong.directory);
    const loadOptions = {
      take: 100,
      skip: 0,
      userData: [],
      filter: metaForm.parseFilter([]),
      isCountQuery: false,
      options: {},
    };
    let res = await metaForm.loadThing(loadOptions);
    const resData = res.data.map((item: { [s: string]: any }) => {
      let newItem: any = {};
      Object.entries(item).forEach(([_key, value]) => {
        let newKey;
        if (pattern.test(_key)) {
          _key = _key.replace('T', '');
          if (_key && Array.isArray(fields)) {
            const temp = fields.find((item) => item.propId === _key);
            if (temp?.propId !== temp?.id) {
              newKey = temp?.id;
            }
          }
        }
        if (newKey) {
          newItem[newKey] = value;
        }
        newItem[_key] = value;
      });
      return newItem;
    });

    formData.current.after = resData;
    setData({ ...formData.current });
  };
  const findDifferentValues = (arr1: any, arr2: any) => {
    const result: any[] = []; // 存储结果的数组
    arr1.forEach((obj1: any) => {
      arr2.forEach((obj2: any) => {
        if (obj1.id === obj2.id) {
          const allKeys = new Set(Object.keys(obj1).concat(Object.keys(obj2)));
          allKeys.forEach((key) => {
            if (obj1[key] !== obj2[key] && key != 'name') {
              if (!result.includes(key)) {
                result.push(key);
              }
            }
          });
        }
      });
    });
    return result;
  };

  if (!formData) {
    return <></>;
  }

  async function addOrUpdate(type: 'add' | 'update', data?: XThing) {
    try {
      const formDataClone = _.cloneDeep(formData);
      const values = await EditModal.showFormEdit({
        form: form,
        fields: fields,
        showSelecteButton: false,
        belong: props.service.belong,
        create: type === 'add',
        initialValues: data,
        formData: formDataClone,
      });

      if (type === 'update') {
        const index = formData.current.after.findIndex((a) => a.id == values.id);
        console.assert(index >= 0, '找不到修改前的数据 ' + values.id);
        formData.current.after[index] = values;
        let changeItems = [...(props.service.model.changeItems || []), values.id];
        props.service.model.changeItems = changeItems;
      } else {
        formData.current.after.push(values);
      }
      setData({ ...formData.current });
    } catch (error) {
      if (error != 'close') {
        console.error(error);
      }
    }
  }

  async function setCopyData(
    thing: schema.XThing,
    fields: model.FieldModel[],
    belong: IBelong,
  ) {
    const changes: Omit<FormChangeEvent, 'formId'>[] = [];

    function onChange(destId: string, value: any) {
      changes.push({ destId, value });
    }
    for (const field of fields) {
      if (field.options?.asyncGeneateConditions?.length) {
        let ret = '';
        for (const rule of field.options.asyncGeneateConditions.sort(
          (pre: { order: any }, next: { order: any }) =>
            Number(pre.order) - Number(next.order),
        )) {
          switch (rule.encodeType.label) {
            case '常量':
              ret += rule.encodeValue;
              break;
            case '时间':
              ret += getAsyncTime(rule.dimensionalAccuracy.label);
              break;
            case '流水':
              var se = await new Sequence(rule.sequence, belong.directory).genValue();
              if (se == '') {
                console.error('生成序号失败!');
              }
              ret += se;
              break;
            default:
              break;
          }
        }
        thing[field.id] = ret;
        onChange(field.id, ret);
      }
    }
  }

  async function copyModal(data: XThing) {
    let num = 0;
    Modal.confirm({
      icon: <></>,
      okText: `确认`,
      cancelText: '关闭',
      onCancel: () => {
        close();
        num = 0;
      },
      content: (
        <div
          style={{
            maxHeight: '20vh',
            width: '100%',
          }}>
          复制数量：
          <InputNumber
            min={0}
            precision={0}
            max={100}
            placeholder="Outlined"
            style={{ width: 200 }}
            onChange={(e) => {
              num = parseInt(e);
            }}
            defaultValue={num}
          />
        </div>
      ),
      onOk: async () => {
        if (num > 0) {
          const res = await kernel.createThing(data?.belongId, [], data.name, num);
          res.data.forEach(async (item: XThing) => {
            await setCopyData(item, fields, props.service.belong);
            formData.current.before.unshift({ ...data, ...item });
            formData.current.after.unshift({ ...data, ...item });
            setData({ ...formData.current });
          });
          num = 0;
        }
      },
    });
  }

  // 限额规则计算可更新数
  const quotaRuleSummery = async (
    metaForm: Form,
    feilds: model.FieldModel[],
    values: schema.XThing[],
    quotaRule: model.Rule<model.RuleType>[],
  ) => {
    const curSpecies = feilds.filter((field) => field.options?.species)[0];
    const selectSpeciesIds = values.map((val) => val[curSpecies.id]);

    const loadOptions: any = {};
    loadOptions.filter = metaForm.parseFilter(loadOptions.filter);
    const classify = metaForm.parseClassify();
    if (loadOptions.filter.length == 0 && Object.keys(classify).length == 0) {
      return { data: [], totalCount: 0 };
    }
    loadOptions.userData = [];
    if (!quotaRule[0].quota) return message.error('请完善配置限额规则');
    const results: any = await metaForm.loadAssetClassQuotaSummary(
      loadOptions,
      curSpecies.code,
      selectSpeciesIds,
      quotaRule[0].quota,
    );
    if (results && results.length > 0) {
      results.map((item: any) => {
        const newItem: any = {};
        for (let key in item) {
          if (item.hasOwnProperty(key)) {
            if (key.startsWith('T')) {
              const newKey = key.slice(1);
              newItem[newKey] = item[key];
            }
          }
        }
        values.forEach((val) => {
          if (newItem[curSpecies.id] === val[curSpecies.id]) {
            if (formData.current.after.every((i) => i.id !== val.id)) {
              formData.current.after.unshift({ ...val, ...newItem });
            }
            if (formData.current.before.every((i) => i.id !== val.id)) {
              formData.current.before.unshift({ ...val, ...newItem });
            }
            setData({ ...formData.current });
          }
        });
      });
    }
  };

  const detailToDetail = async (
    values: schema.XThing[],
    detailToDetailRule: model.Rule<model.RuleType>,
    actionType: 'add' | 'remove',
  ) => {
    let mergeArr: schema.XThing[] | schema.XOrder[] = [];
    if (actionType === 'add') {
      mergeArr = _.unionBy(formData.current.after, values, 'id');
    } else if (actionType === 'remove') {
      mergeArr = [...values];
    }
    const isOrder = mergeArr.some((item: any) => item.orderNumber);
    let details: any[] = [];
    let changeItems: any[] = [];
    if (isOrder) {
      const target = props.service.target;
      const isOrdeForm = mergeArr.some((item: any) => item.itemList);
      const detailFormFields =
        props.service.model.fields[detailToDetailRule.detailToDetail!.forms![0].id];
      if (Array.isArray(mergeArr) && isOrdeForm) {
        let pendingAssets: Record<string, any> = {};
        const promises = mergeArr.map((itm) => {
          return Promise.all(
            itm.itemList.map(async (itm1: any) => {
              if (itm1.pendingCount <= 0) return;
              // 卖方
              if (itm.seller === target.id) {
                if (pendingAssets?.hasOwnProperty(itm1.id)) return;
                let result = await target.resource.thingColl.find([itm1.id]);
                // 卖方：商品id相同，订单编号不管
                if (Array.isArray(result) && result.length > 0) {
                  result = result.map((item: { [s: string]: any }) => {
                    let newItem: any = {
                      orderNumber: itm.orderNumber,
                    };
                    Object.entries(item).forEach(([_key, value]) => {
                      if (pattern.test(_key)) {
                        _key = _key.replace('T', '');
                      }
                      const item = detailFormFields.find((item) => item.propId === _key);
                      if (item) {
                        newItem[item.id] = value;
                      }
                      newItem[_key] = value;
                    });
                    return newItem;
                  });
                }
                pendingAssets[itm1.id] = result;
              } else {
                if (pendingAssets[itm.orderNumber]?.hasOwnProperty(itm1.id)) return;
                const result = await target.resource.thingColl.loadSpace({
                  options: {
                    match: {
                      recordId: itm1.id,
                      orderNumber: itm.orderNumber,
                    },
                    project: {
                      resource: 0,
                      archives: 0,
                    },
                  },
                });
                let resource: any = {};
                try {
                  resource = itm1?.resource ? JSON.parse(itm1.resource) : {};
                } catch (error) {
                  console.warn('Failed to parse resource:', itm1.resource, error);
                }
                const asset = Object.entries({
                  ...resource,
                  ...itm1,
                  count: resource?.count || itm1?.count,
                  belongId: itm.buyer,
                }).reduce((acc, [_key, value]) => {
                  const newKey = _key.replace(/^T/, '');
                  const item = detailFormFields.find((item) => item.propId === newKey);
                  if (item) {
                    acc[item.id] = value;
                  } else {
                    acc[newKey] = value;
                  }
                  return acc;
                }, {} as Record<string, any>);

                // 买家处理了一部分的情况
                if (Array.isArray(result) && result.length > 0) {
                  const data1 = result.map((item: { [s: string]: any }) => {
                    let newItem: any = {};
                    Object.entries(item).forEach(([_key, value]) => {
                      if (pattern.test(_key)) {
                        _key = _key.replace('T', '');
                      }
                      const item = detailFormFields.find((item) => item.propId === _key);
                      if (item) {
                        newItem[item.id] = value;
                      }
                      newItem[_key] = value;
                    });
                    return newItem;
                  });
                  data1.map(async (change: any) => {
                    Object.keys(asset).forEach((key) => {
                      Object.keys(change).forEach((changeKey) => {
                        if (
                          key.includes(changeKey) &&
                          key !== changeKey &&
                          typeof asset[`T${changeKey}`] === 'number'
                        ) {
                          asset[`T${changeKey}`] = new Decimal(asset[`T${changeKey}`])
                            .minus(new Decimal(change[changeKey]))
                            .toNumber();
                        }
                        if (
                          key === changeKey &&
                          typeof change[changeKey] === 'number' &&
                          (/^(?:\d{18}|T\d+)$/.test(changeKey) ||
                            ['count'].includes(changeKey))
                        ) {
                          asset[key] = new Decimal(asset[key])
                            .minus(new Decimal(change[changeKey]))
                            .toNumber();
                        }
                      });
                    });
                  });
                }
                (pendingAssets[itm.orderNumber] ||= {})[itm1.id] = [asset];
              }
            }),
          );
        });
        await Promise.all(promises);
        const detailPrimaryData =
          props.service.model.data[detailToDetailRule.detailToDetail!.forms![0].id];
        const detailData = detailPrimaryData[0]['after'];

        // 处理删除了资产卡片，又重新把重复的订单选择进来的情况
        if (Array.isArray(detailData) && detailData.length > 0) {
          detailData.forEach((item: any) => {
            const pdAssets =
              pendingAssets?.[item.orderNumber]?.[item.recordId] ??
              pendingAssets?.[item.recordId];
            if (!pdAssets) return;
            let asset = Array.isArray(pdAssets) ? pdAssets[0] : pdAssets;
            // 买方处理
            if (asset.orderNumber === item.orderNumber) {
              Object.keys(asset).forEach((key) => {
                Object.keys(item).forEach((changeKey) => {
                  if (
                    key.includes(changeKey) &&
                    key !== changeKey &&
                    asset[`T${changeKey}`] &&
                    typeof asset[`T${changeKey}`] === 'number'
                  ) {
                    asset[key] -= item[changeKey];
                  }
                  if (
                    key === changeKey &&
                    typeof item[changeKey] === 'number' &&
                    (/^(?:\d{18}|T\d+)$/.test(changeKey) || ['count'].includes(changeKey))
                  ) {
                    asset[key] -= item[key];
                  }
                });
              });
            }
          });
        }

        for (const itm of mergeArr) {
          let handleCount = 0;
          for (const itm1 of itm.itemList) {
            if (itm1.pendingCount <= 0) continue;
            const pdAssets =
              itm.seller === target.id
                ? pendingAssets?.[itm1.id]
                : pendingAssets?.[itm.orderNumber]?.[itm1.id];
            let asset = _.cloneDeep(pdAssets);
            if (!asset) {
              console.warn(`未找到资产，itm1.id: ${itm1.id}`);
              continue;
            }

            const splitRule = props.node.formRules.find(
              (i) => i.type === 'combination' && i.applyType === '拆分',
            );
            if (!splitRule) continue;
            const splitInstance = new SplitHandler(props.service, asset, splitRule);

            let data = {
              ...itm1,
              ...(asset[0] || {}),
              orderNumber: itm.orderNumber,
            };
            const result = await splitInstance.splitOrder(
              data,
              itm1.pendingCount,
              itm.seller === target.id ? itm.seller : itm.buyer,
            );

            const newResult = _.cloneDeep(result.before);
            if (itm.seller === target.id) {
              Object.assign(pendingAssets, {
                [itm1.id]: newResult,
              });
            } else {
              Object.assign(pendingAssets, {
                [itm.orderNumber]: {
                  [itm1.id]: newResult,
                },
              });
            }
            details = details.concat(result.after);
            const totals = _.mapValues(_.groupBy(details, 'recordId'), (v) => v.length);
            itm1.processedCount = itm1.purchaseQuantity - itm1.pendingCount; // 已处理数量
            itm1.pendingCount = itm1.pendingCount - (totals[itm1.id] || 0);
            handleCount += result.after.length;
            if (itm.seller === target.id) {
              changeItems = changeItems.concat(result.after);
            }
          }

          itm.pendingCount = itm.pendingCount - handleCount;
          if (itm.pendingCount === 0) {
            itm.orderStatus = 'COMPLETED';
          }
        }
        props.service.model['changeItems'] = [...changeItems, ...detailData];
        props.service.command.emitter('change', 'combination', {
          formId: props.form.id,
          data: mergeArr,
        });
        // 删除订单，更新商品列表
        if (details.length === 0) {
          const detailPrimaryData =
            props.service.model.data[detailToDetailRule.detailToDetail!.forms![0].id];
          const detailData = detailPrimaryData[0]['after'];
          const remainingAssetIds = new Set(
            mergeArr.map((item) => item.orderNumber).flat(),
          );
          const filteredAsset = detailData.filter((asset) =>
            remainingAssetIds.has(asset.orderNumber),
          );
          details = filteredAsset;
        } else {
          const detailPrimaryData =
            props.service.model.data[detailToDetailRule.detailToDetail!.forms![0].id];
          const detailData = detailPrimaryData[0]['after'];
          details = _.unionBy(details, detailData, 'id');
        }
      } else {
        // 子子表移除后，要给主表加上 待处理数量
        const detailPrimary = props.node.detailForms.at(0);

        if (detailPrimary && detailPrimary.id) {
          const detailPrimaryData = props.service.model.data[detailPrimary.id];
          const detailData = detailPrimaryData[0]['after'];

          const remainingAssetIds = new Set(
            mergeArr.map((asset: any) => asset.orderNumber),
          );
          const filteredOrders = detailData.filter((order) => {
            const hasMatchingItem = order.itemList.some((item: any) =>
              remainingAssetIds.has(item.orderNumber),
            );
            return hasMatchingItem;
          });
          const orderItems = mergeArr;
          const orderInfo = filteredOrders;
          //  根据 orderNumber 进行分组
          const groupedByOrder = _.groupBy(orderItems, 'orderNumber');

          //  统计每个分组中 recordId 出现的次数
          const totals = _.mapValues(groupedByOrder, (items) => {
            return _.countBy(items, 'recordId');
          });
          orderInfo.forEach((order) => {
            order.itemList.forEach((item: any) => {
              if (totals[item.orderNumber]) {
                const count = totals?.[item.orderNumber]?.[item.id] || 0;
                // 已处理数量
                item.processedCount = count;
              }
            });
          });

          // 更新订单信息
          const updatedOrderInfo = orderInfo.map((order) => {
            const updatedOrder = _.cloneDeep(order);
            updatedOrder.itemList = updatedOrder.itemList.map((item: any) => {
              if (totals[item.orderNumber]) {
                //  待处理数量  =  购买数量 - 已处理数量
                item.pendingCount = item.purchaseQuantity - item.processedCount;
              }
              return item;
            });
            updatedOrder.pendingCount = _.sumBy(updatedOrder.itemList, 'pendingCount');
            updatedOrder.orderStatus =
              updatedOrder.pendingCount > 0 ? 'PROCESSING' : 'COMPLETED';
            return updatedOrder;
          });
          props.service.command.emitter('change', 'combination', {
            formId: detailPrimary.id,
            data: updatedOrderInfo,
          });
        }
        props.service.model['changeItems'] = mergeArr as any;
        details = mergeArr;
      }
    } else {
      const loadOptions: model.LoadOptions = {
        options: {
          match: {
            isDeleted: false,
            id: { $in: mergeArr.map((item) => item.id) },
          },
        },
      };
      const metaForm = new Form(form, props.service.belong.directory);
      const result = await metaForm.loadArchives(loadOptions);
      const resultData = result.data || [];
      const mergedResult = _.mergeWith(
        _.keyBy(mergeArr, 'id'),
        _.keyBy(resultData, 'id'),
        (a, b) => ({ archives: Object.values(b.archives)[0] || {}, ...a }),
      );

      const instanceDetails = _.values(mergedResult).map(async (instance: any) => {
        const { archives } = instance;
        const detail = await orgCtrl.work.loadInstanceDetail(
          archives.id || archives._id,
          archives.shareId,
          archives.belongId,
        );
        const data = detail?.data ? JSON.parse(detail.data) : {};
        const billsField = instance[detailToDetailRule.detailToDetail!.billsField!.id];
        const newDetails = data.node.detailForms.flatMap((detailForm: schema.XForm) =>
          data.data[detailForm.id][0].after.map((item: any) => ({
            [detailToDetailRule.detailToDetail!.detailField!.id]: billsField,
            ...item,
          })),
        );
        details.push(...newDetails);
      });
      await Promise.all(instanceDetails);
    }
    if (mergeArr.length === 0) {
      const detailPrimary = props.node.detailForms.at(0);
      props.service.command.emitter('change', 'combination', {
        formId: detailPrimary?.id,
        data: [],
      });
    }
    props.service.command.emitter('change', 'combination', {
      formId: detailToDetailRule.detailToDetail!.forms![0].id,
      data: details,
    });
  };

  async function updateModal(info: model.operationButtonInfo) {
    const metaForm = new Form(info.form?.metadata, props.service.belong.directory);
    const fields = await metaForm.loadFields();
    let FormProps = {
      form: info.form?.metadata,
      fields: fields,
      belong: props.service.belong,
      onSave: (values: schema.XThing[]) => {
        const hasQuotaRule = props.node.formRules.filter(
          (i) => i.type === 'assignment' && i.ruleType === 'quota',
        );
        if (hasQuotaRule.length > 0) {
          quotaRuleSummery(metaForm, fields, values, hasQuotaRule);
        } else {
          values.forEach((item) => {
            if (formData.current.after.every((i) => i.id !== item.id)) {
              formData.current.after.unshift(item);
            }
            if (formData.current.before.every((i) => i.id !== item.id)) {
              formData.current.before.unshift({ ...item });
            }
          });
          setData({ ...formData.current });
        }
      },
    };
    if (info.type === 'choice') {
      EditModal.showFormSelect(FormProps);
    } else if (info.type === 'syncData') {
      EditModal.showSyncModal(FormProps);
    } else {
      EditModal.SummaryFormModal(FormProps);
    }
  }

  const showBtn = () => {
    let arr: any[] = [];
    if (info.operationButton && info.operationButton.length > 0) {
      info.operationButton.forEach((item) => {
        if (item?.scene !== 'mobile') {
          arr.push({
            name: 'add',
            location: 'after',
            widget: 'dxButton',
            options: {
              text: item.name,
              icon: 'add',
              onClick: async () => {
                await updateModal(item);
              },
            },
            visible: props.allowEdit,
          });
          if (item?.code === 'code') {
            arr.push({
              name: 'add',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '分类存量导入',
                icon: 'add',
                onClick: async () => {
                  const values = deepClone(fields);
                  values.unshift({
                    id: 'id',
                    name: '唯一标识',
                    code: 'id',
                    valueType: '描述型',
                    remark: '唯一标识',
                  } as model.FieldModel);
                  const excel = new el.Excel(
                    props.service.belong,
                    el.getAnythingSheets(form, values, 'id'),
                  );
                  const modal = Modal.info({
                    icon: <></>,
                    okText: '关闭',
                    width: 610,
                    title: form.name + '导入',
                    className: 'uploader-model',
                    maskClosable: true,
                    content: (
                      <Uploader
                        templateName={form.name}
                        excel={excel}
                        fields={fields}
                        finished={(_, errors) => {
                          modal.destroy();
                          if (errors.length > 0) {
                            showErrors(errors);
                            return;
                          }
                          directImport(
                            excel.handlers[0].sheet.data,
                            formData.current,
                            () => setData({ ...formData.current }),
                          );
                        }}
                      />
                    ),
                  });
                },
              },
              visible: props.allowEdit,
            });
          }
        }
      });
    }
    return arr;
  };

  const loadMenus = () => {
    if (props.allowEdit) {
      var items = [
        {
          key: 'remove',
          label: '移除',
          icon: <AiFillRest fontSize={22} />,
        },
      ];
      if (form.isCopy) {
        items.unshift({
          key: 'copy',
          label: '复制数据',
          icon: <AiFillCopy fontSize={22} />,
        });
      }
      if (operateRule.allowEdit) {
        items.unshift({
          key: 'update',
          label: '更新',
          icon: <AiFillEdit fontSize={22} />,
        });
      }
      return {
        items: items,
        async onMenuClick(key: string, data: XThing) {
          switch (key as DetailOperationType) {
            case 'update':
              addOrUpdate('update', data);
              break;
            case 'copy':
              copyModal(data);
              break;
            case 'remove':
              formData.current.before = formData.current.before.filter(
                (i) => i.id != data.id,
              );
              formData.current.after = formData.current.after.filter(
                (i) => i.id != data.id,
              );
              const detailToDetailRule = props.node.formRules.find(
                (i) => i.ruleType === 'detailToDetail',
              );
              if (detailToDetailRule) {
                detailToDetail(formData.current.after, detailToDetailRule, 'remove');
              }
              setSelectKeys([]);
              setData({ ...formData.current });
              break;
          }
        },
      };
    } else {
      return {
        items: [
          {
            key: 'detail',
            label: '详情',
            icon: <AiFillEdit fontSize={22} />,
          },
          {
            key: 'printEntity',
            label: '标签打印',
            icon: <MdPrint fontSize={22} color={Theme.FocusColor} />,
            hide:
              !props.allowLabelPrint || !form?.print ? true : form.print?.config?.hide,
          },
        ],
        onMenuClick(key: string, data: XThing) {
          switch (key as DetailOperationType) {
            case 'detail':
              command.emitter(
                'executor',
                'open',
                {
                  ...data,
                  fields: fields,
                  formId: form.id,
                  typeName: '物详情',
                  key: data.id,
                },
                'preview',
              );
              break;
            case 'printEntity':
              command.emitter(
                'executor',
                'printEntity',
                { metadata: form, fields },
                'multiple',
                [data],
              );
              break;
          }
        },
      };
    }
  };
  const loadFormData = (things: schema.XThing[], tempId: string) => {
    return new CustomStore({
      key: 'id',
      async load(loadOptions: any) {
        if (tempId != undefined && tempId.length > 0) {
          loadOptions.userData = [];
          loadOptions.options = loadOptions.options || {};
          loadOptions.options.match = {
            ...loadOptions.options.match,
            tempId: tempId,
          };
          let result = await kernel.collectionLoad<XThing[]>(
            props.service.target.id,
            props.service.target.belongId,
            props.service.target.relations,
            '-work-temp-data',
            loadOptions,
          );
          if (result.data.length > 0) {
            return result;
          } else {
            result = await kernel.collectionLoad<XThing[]>(
              props.service.belong.id,
              props.service.belong.belongId,
              props.service.belong.relations,
              '-work-temp-data',
              loadOptions,
            );
            if (result) {
              return result;
            }
          }
          return result;
        } else {
          let redRowRule = '';
          let filterRedRowExp = form.options?.dataRange?.filterRedRowExp;
          if (!things.length) return { data: [], totalCount: 0 };
          if (!filterRedRowExp) return { data: things, totalCount: things.length };
          const data = cloneDeep(
            things.map((v) => {
              delete v.redRowFlag;
              return v;
            }),
          );
          try {
            if (filterRedRowExp) {
              form.attributes.forEach((item) => {
                if (filterRedRowExp!.includes(item.property!.id)) {
                  filterRedRowExp = filterRedRowExp!.replaceAll(
                    `T${item.property!.id}`,
                    item.id,
                  );
                }
              });
              redRowRule = JSON.parse(filterRedRowExp);
            }
            // eslint-disable-next-line no-empty
          } catch (_e) {}
          if (data && data.length > 0 && redRowRule) {
            const d = await new ArrayStore({ data: data }).load({ filter: redRowRule });
            d.forEach((item) => {
              const index = data.findIndex((j) => j.id === item.id);
              if (index > -1) data[index]['redRowFlag'] = true;
            });
          }
          return { data: data ?? [], totalCount: data.length };
        }
      },
    });
  };
  const getLoding = () => {
    if (operateRule.autoAll && !operateRule.isAutoAll && !data.afterTempId) {
      return true;
    }
    return data.afterTempId != undefined && data.afterTempId.length > 0;
  };
  return (
    <>
      <GenerateThingTable
        form={props.form}
        fields={loadFields()}
        height={500}
        dataIndex={'attribute'}
        selection={
          props.allowEdit
            ? {
                mode: 'multiple',
                allowSelectAll: true,
                selectAllMode: 'allPages',
                showCheckBoxesMode: 'always',
              }
            : undefined
        }
        remoteOperations={getLoding()}
        differences={differences}
        onSelectionChanged={(e) => setSelectKeys(e.selectedRowKeys)}
        onExporting={(e) => exportToExcel(e, props.form)}
        toolbar={{
          visible: true,
          items: [
            ...showBtn(),
            {
              name: 'add',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '新增',
                icon: 'add',
                onClick: () => {
                  addOrUpdate('add');
                },
              },
              visible: props.allowEdit && operateRule['allowAdd'],
            },
            {
              name: 'import',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '导入匹配',
                icon: 'add',
                onClick: async () => {
                  const values = deepClone(fields);
                  values.unshift({
                    id: 'id',
                    name: '唯一标识',
                    code: 'id',
                    valueType: '描述型',
                    remark: '唯一标识',
                  } as model.FieldModel);
                  const excel = new el.Excel(
                    props.service.belong,
                    el.getAnythingSheets(
                      form,
                      values.filter((i) => i.name === form.matchImport || ''),
                      'code',
                    ),
                  );
                  const modal = Modal.info({
                    icon: <></>,
                    okText: '关闭',
                    width: 610,
                    title: form.name + '导入',
                    className: 'uploader-model',
                    maskClosable: true,
                    content: (
                      <Uploader
                        templateName={form.name}
                        excel={excel}
                        fields={fields}
                        finished={(_, errors) => {
                          modal.destroy();
                          if (errors.length > 0) {
                            showErrors(errors);
                            return;
                          }
                          matching(
                            props.service.belong,
                            form,
                            excel.handlers[0].sheet.data,
                            formData.current,
                            fields,
                            () => setData({ ...formData.current }),
                          );
                        }}
                      />
                    ),
                  });
                },
              },
              visible:
                props.allowEdit &&
                operateRule['allowSelect'] &&
                fields.filter((i) => i.name === form.matchImport || '').length > 0,
            },
            {
              name: 'import',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '导入变更',
                icon: 'add',
                onClick: async () => {
                  const values = deepClone(fields);
                  values.unshift({
                    id: 'id',
                    name: '唯一标识',
                    code: 'id',
                    valueType: '描述型',
                    remark: '唯一标识',
                  } as model.FieldModel);
                  const excel = new el.Excel(
                    props.service.belong,
                    el.getAnythingSheets(form, values, 'code'),
                  );
                  const modal = Modal.info({
                    icon: <></>,
                    okText: '关闭',
                    width: 610,
                    title: form.name + '导入',
                    className: 'uploader-model',
                    maskClosable: true,
                    content: (
                      <Uploader
                        templateName={form.name}
                        excel={excel}
                        fields={fields}
                        belondId={props.service.belong.id}
                        finished={(_, errors) => {
                          modal.destroy();
                          if (errors.length > 0) {
                            showErrors(errors);
                            return;
                          }
                          matching(
                            props.service.belong,
                            form,
                            excel.handlers[0].sheet.data,
                            formData.current,
                            fields,
                            () => setData({ ...formData.current }),
                            'matchChange',
                          );
                        }}
                      />
                    ),
                  });
                },
              },
              visible:
                props.allowEdit &&
                operateRule['allowSelect'] &&
                fields.filter((i) => i.name === form.matchImport || '').length > 0,
            },
            {
              name: 'selectFile',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '选择文件',
                icon: 'add',
                onClick: async () => {
                  setCenter(
                    <OpenFileDialog
                      accepts={['目录']}
                      rootKey={props.service.belong.directory.key}
                      multiple
                      onOk={(files) => {
                        files.forEach((item) => {
                          let thing = item.metadata as any as schema.XThing;
                          if (formData.current.after.every((i) => i.id !== item.id)) {
                            thing = { ...thing };
                            let avatar = parseAvatar(thing.icon);
                            if (avatar) {
                              thing.icons = JSON.stringify([avatar]);
                            }
                            for (const key of Object.keys(thing)) {
                              if (Array.isArray(thing[key])) {
                                thing[key] = undefined;
                              }
                            }
                            formData.current.after.unshift({ ...thing });
                          }
                        });
                        setData({ ...formData.current });
                        setCenter(<></>);
                      }}
                      onCancel={() => setCenter(<></>)}
                    />,
                  );
                },
              },
              visible: props.allowEdit && operateRule.allowSelectFile,
            },
            {
              name: 'import',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '导入新增',
                icon: 'add',
                onClick: async () => {
                  const values = deepClone(fields);
                  values.unshift({
                    id: 'id',
                    name: '唯一标识',
                    code: 'id',
                    valueType: '描述型',
                    remark: '唯一标识',
                  } as model.FieldModel);
                  const excel = new el.Excel(
                    props.service.belong,
                    el.getAnythingSheets(form, values, 'id'),
                  );
                  const modal = Modal.info({
                    icon: <></>,
                    okText: '关闭',
                    width: 610,
                    className: 'uploader-model',
                    title: form.name + '导入',
                    maskClosable: true,
                    content: (
                      <Uploader
                        templateName={form.name}
                        excel={excel}
                        belondId={form.shareId}
                        finished={(_, errors, conditions, cardconditions) => {
                          modal.destroy();
                          if (errors.length > 0) {
                            showErrors(errors);
                            return;
                          }
                          generating(
                            props.service.belong,
                            form.name,
                            fields,
                            excel.handlers[0].sheet.data,
                            formData.current,
                            () => setData({ ...formData.current }),
                            conditions,
                            cardconditions,
                          );
                        }}
                        type="add"
                      />
                    ),
                  });
                },
              },
              visible: props.allowEdit && operateRule['allowAdd'],
            },
            {
              name: 'importMatch',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '匹配导入',
                icon: 'add',
                onClick: async () => {
                  const values = deepClone(fields);
                  values.unshift({
                    id: 'id',
                    name: '唯一标识',
                    code: 'id',
                    valueType: '描述型',
                    remark: '唯一标识',
                  } as model.FieldModel);
                  const excel = new el.Excel(
                    props.service.belong,
                    el.getAnythingSheets(form, values, 'id'),
                  );
                  const modal = Modal.info({
                    icon: <></>,
                    okText: '关闭',
                    width: 610,
                    className: 'uploader-model',
                    title: form.name + '导入',
                    maskClosable: true,
                    content: (
                      <Uploader
                        templateName={form.name}
                        excel={excel}
                        belondId={form.shareId}
                        finished={(_, errors, conditions, cardconditions) => {
                          modal.destroy();
                          if (errors.length > 0) {
                            showErrors(errors);
                            return;
                          }
                          generatingMatch(
                            props.service.belong,
                            form.name,
                            fields,
                            excel.handlers[0].sheet.data,
                            formData.current,
                            () => setData({ ...formData.current }),
                            conditions,
                            cardconditions,
                          );
                        }}
                        type="add"
                      />
                    ),
                  });
                },
              },
              visible: props.allowEdit && operateRule['allowAdd'],
            },
            {
              name: 'edit',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '变更',
                icon: 'edit',
                onClick: async () => {
                  const values = await EditModal.showFormEdit({
                    form: form,
                    fields: fields,
                    belong: props.service.belong,
                    create: false,
                  });

                  formData.current.after = formData.current.after.map((item) => {
                    if (selectKeys.includes(item.id)) {
                      Object.keys(values).forEach((k) => {
                        item[k] = values[k];
                      });
                    }
                    return item;
                  });
                  setData({ ...formData.current });
                },
              },
              visible:
                props.allowEdit && operateRule['allowEdit'] && selectKeys.length > 0,
            },
            {
              name: 'select',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '选择',
                icon: 'bulletlist',
                onClick: () => {
                  let space: ITarget = props.service.belong;
                  if (props.info.selectBelong) {
                    space = props.service.target;
                  }
                  EditModal.showFormSelect({
                    form: form,
                    fields: fields,
                    belong: space,
                    onSave: async (values) => {
                      const detailToDetailRule = props.node.formRules.find(
                        (i) => i.ruleType === 'detailToDetail',
                      );
                      if (detailToDetailRule) {
                        detailToDetail(values, detailToDetailRule, 'add');
                      }
                      await props.service.beforeSelectedData(values, fields);
                      if (props.info.allowGenerate) {
                        const result = await kernel.createThing(
                          props.service.belong.id,
                          [props.service.belong.id],
                          form.name,
                          values.length,
                        );
                        for (let index = 0; index < values.length; index++) {
                          const value = values[index];
                          const thing = result.data[index];
                          for (const key of Object.keys(value)) {
                            if (!thing[key]) {
                              thing[key] = value[key];
                            }
                          }
                          formData.current.after.push(thing);
                        }
                      } else {
                        values.forEach((item) => {
                          if (formData.current.after.every((i) => i.id !== item.id)) {
                            formData.current.after.unshift(item);
                          }
                          if (formData.current.before.every((i) => i.id !== item.id)) {
                            formData.current.before.unshift({ ...item });
                          }
                        });
                      }
                      setData({ ...formData.current });
                    },
                  });
                },
              },
              visible: props.allowEdit && operateRule['allowSelect'],
            },
            {
              name: 'remove',
              location: 'after',
              widget: 'dxButton',
              options: {
                text: '移除',
                icon: 'remove',
                onClick: () => {
                  formData.current.before = formData.current.before.filter(
                    (i) => !selectKeys.includes(i.id),
                  );
                  formData.current.after = formData.current.after.filter(
                    (i) => !selectKeys.includes(i.id),
                  );

                  const detailToDetailRule = props.node.formRules.find(
                    (i) => i.ruleType === 'detailToDetail',
                  );
                  if (detailToDetailRule) {
                    detailToDetail(formData.current.after, detailToDetailRule, 'remove');
                  }

                  setSelectKeys([]);
                  setData({ ...formData.current });
                },
              },
              visible: props.allowEdit && selectKeys.length > 0,
            },
            {
              name: 'exportButton',
              location: 'after',
            },
            {
              name: 'print',
              location: 'after',
              widget: 'dxButton',
              visible:
                props.allowLabelPrint &&
                form?.print &&
                (form.print.config?.hide === void 0 || form.print.config?.hide === false),
              options: {
                icon: 'print',
                onClick: () => {
                  if (!form.print) return message.error('请先配置打印模板');
                  if (formData.current.after.length === 0)
                    return message.error('请选择需要打印的数据');
                  command.emitter(
                    'executor',
                    'printEntity',
                    { metadata: form, fields },
                    'multiple',
                    formData.current.after,
                  );
                },
              },
            },
            {
              name: 'columnChooserButton',
              location: 'after',
            },
            {
              name: 'searchPanel',
              location: 'after',
            },
          ],
        }}
        dataMenus={loadMenus()}
        dataSource={loadFormData(data.after, data.afterTempId)}
        beforeSource={data.before}
      />
      {center}
    </>
  );
};

interface IProps {
  service: WorkFormService;
  node: model.WorkNodeModel;
  allowLabelPrint?: boolean;
  splitDetailFormId?: string;
  tabBarExtraContent?: TabBarExtraContent;
  instanceData?: model.InstanceDataModel;
}

const DetailForms: React.FC<IProps> = (props) => {
  if (props.node.detailForms.length < 1) return <></>;
  const [activeTabKey, setActiveTabKey] = useState(
    props.splitDetailFormId || props.node.detailForms[0].id,
  );
  const loadItems = () => {
    const items = [];
    const detailForms = props.splitDetailFormId
      ? props.node.detailForms.filter((i) => i.id === props.splitDetailFormId)
      : props.node.detailForms;
    for (const form of detailForms) {
      let info =
        props.node.forms.find((item) => item.id == form.id) ?? ({} as model.FormInfo);
      if (
        props.service.model.rules?.find(
          (a) => a.destId == form.id && a.typeName == 'visible' && !a.value,
        )
      ) {
        continue;
      }
      items.push({
        key: form.id,
        forceRender: true,
        label: form.name,
        children: (
          <DetailTable
            index={items.length}
            activeTabKey={activeTabKey}
            allowEdit={props.service.allowEdit}
            info={info}
            form={form}
            allowLabelPrint={props.allowLabelPrint}
            node={props.node}
            service={props.service}
            instanceData={props.instanceData}
          />
        ),
      });
    }
    return items;
  };
  return (
    <Tabs
      items={loadItems()}
      activeKey={activeTabKey}
      tabBarExtraContent={props.tabBarExtraContent}
      onChange={(key) => setActiveTabKey(key)}
    />
  );
};

export default DetailForms;
